APIs & Integrations
Outbound HTTP
Structr can call external HTTP services from any script context. The functions below share one shape:
the URL first, then a body where the verb has one, then the content type, then a single options object.
Functions
| Function | Signature | Returns |
|---|---|---|
$.GET |
url [, contentType [, options ]] |
{ body, status, headers } |
$.HEAD |
url [, options ] |
{ body, status, headers }, body always null |
$.POST |
url, body [, contentType [, options ]] |
{ body, status, headers } |
$.PUT |
url, body [, contentType [, options ]] |
{ body, status, headers } |
$.PATCH |
url, body [, contentType [, options ]] |
{ body, status, headers } |
$.DELETE |
url [, body [, contentType [, options ]]] |
{ body, status, headers } |
$.FETCH |
url, method [, body [, contentType [, options ]]] |
{ body, status, headers } |
$.POSTMultiPart |
url, partsMap [, options ] |
{ body, status, headers } |
status is an integer. Use $.FETCH for a method the others do not cover.
{
let response = $.GET('https://api.example.com/projects', 'application/json', { parseResponse: true });
if (response.status === 200) {
return response.body.results;
}
}
Options
These are accepted by every function:
| Option | Meaning |
|---|---|
username, password |
Basic authentication |
preemptive |
Send the credentials with the first request instead of waiting for a 401 |
headers |
Additional request headers, merged over $.addHeader() |
timeout |
Seconds to wait, for both connecting and reading. Without it the defaults application.httphelper.timeouts.connect (60 seconds to establish the connection) and application.httphelper.timeouts.socket (600 seconds of inactivity between two data packets) apply. |
redirects |
Whether to follow redirects |
validateCertificates |
Whether to verify TLS certificates |
These are accepted only where they mean something, and are an error elsewhere:
| Option | Where | Meaning |
|---|---|---|
parseResponse |
all but $.HEAD |
Parse the response body as JSON |
selector |
$.GET |
A CSS selector applied to a text/html response |
binaryResponse |
$.GET, $.POST |
Return the response body as a stream |
An unsupported option is rejected with a message naming the function and the key. This is deliberate: an
option that was accepted and ignored, such as a timeout that never applied, would only show up much
later as a call that hung.
The Character Set Belongs to the Content Type
There is no separate charset argument. Put it where HTTP puts it:
$.POST(url, body, 'application/json; charset=ISO-8859-1');
Sending a File
Pass a File as the body and its content is streamed from the storage backend, without base64 or a
multipart envelope:
$.PUT('https://api.example.com/documents/42', $.first($.find('File', 'name', 'report.pdf')), 'application/pdf');
A stream cannot be sent twice, which matters for authentication: basic credentials are normally sent only
after the server answers 401, and answering means repeating the request. Set preemptive when sending a
file to a service that needs credentials, or the call is refused:
$.PUT(url, file, 'application/pdf', { username: 'u', password: 'p', preemptive: true });
Use $.POSTMultiPart when the endpoint expects a form upload with several parts.
Guidelines
- Always check
status. Nothing about a failed request throws. An HTTP error arrives as its own
status, so a404isstatus: 404, and a request that never reached the server at all isstatus: 0
with the reason inerror. Only an unusable call throws, see below. - Prefer
parseResponseover parsing by hand. It uses the same JSON handling as the rest of Structr. - Set a
timeoutfor anything a user waits on. Without one the call waits for the configured defaults,
60 seconds to connect and 600 seconds for data, which is generous. - Keep
validateCertificateson. Turning it off disables the check for that call entirely, not just
for an unknown authority. - Omit an argument you do not need.
$.POST(url, body, { timeout: 5 })is understood: an options
object is recognised even when the content type before it is left out.
Errors
There are three outcomes, and only the last one throws.
| Outcome | Result |
|---|---|
| The server answered | status is what it sent, body may be null for a 204 or a bodyless error |
| No answer: DNS, connection refused, TLS, timeout | status: 0, body: null, error describes the failure |
| The call itself is unusable | throws a FrameworkException |
{
let response = $.GET('https://api.example.com/thing');
if (response.status === 0) {
$.log('service unreachable: ' + response.error);
} else if (response.status !== 200) {
$.log('service returned ' + response.status);
} else {
return response.body;
}
}
A status of 0 rather than an exception matters in StructrScript, which has no try/catch: a throw
there could not be handled at all. What still throws is a call that could never be made - a malformed URL
(400), a scheme other than http or https (400), a URL with no host (400), an address in an internal
network (403), or a URL outside application.httphelper.urlwhitelist (422).
Caveats
- A response body is text unless you ask otherwise. For binary data use
binaryResponseon$.GETor
binaryResponseon$.POST, which return a stream. A stream can be read once. $.DELETEmay carry a body, which is permitted by HTTP but rejected by some servers.headersare merged over$.addHeader(), so an option with the same name wins.- These functions are not proxied through the settings used by the crawler; they connect directly.
Signatures changed in 7.0. See the Migration chapter for the previous form and for the automatic rewrite.